<?php
/**
 * Created by PhpStorm.
 * User: s.utkin
 * Date: 30.09.14
 * Time: 10:26
 */

namespace Jobs\Resources;


use PublishedResources\PublishedPackagesConfig;
use Resources\Config\PackagesConfig;
use Resources\Manager;
use Resources\Publisher;
use Runtime\PublishedResourcesConfig;

class CheckChangesAction extends \Action {

	public static $runtimeConfigPath = null;
	/**
	 * Проверяет, изменились ли исходники ресурсов с момента их пуликации.
	 * Если было изменение - удалет из конфига-кэша соответствующие эементы.
	 */
	protected function run()
	{
		$this->response->noRender(true);
		$startTime = time();

		static::$runtimeConfigPath = realpath(PINENUT_APPLICATION . '/../runtime/PublishedResources/PublishedPackagesConfig.php');

		# TODO: на продакшене запускать один раз в час, например.
		while ((time() - $startTime) < 60) {
			$this->check();
			sleep(3);
		}
	}	

	protected function check() {

		$packagesForPublish = [];
		$runtimeConfigElements = Publisher::getRuntimeConfig();

		$publicDir = realpath(PINENUT_APPLICATION . '/../public');

		# Пробегаемся по элементам runtime-массива
		foreach ($runtimeConfigElements as $packageName => $packageVersion) {

			# Получаем имя класса с конфигом пакета
			$packageClassName = PackagesConfig::get($packageName);
			
			// если были на живую переименования - пакет мог перестать существовать - пропускаем его
			if (empty($packageClassName)) {
				continue;
			}
			
			$packageRelativeDirName = Publisher::getPackageRelativeDir($packageClassName);

			if (!class_exists($packageClassName) || !method_exists($packageClassName, 'get')) {
				throw new \Exception("Wrong package config: $packageClassName");
			}

			# Получаем конфиг пакета
			$packageConfig = $packageClassName::get();

			# Проверряем файлы
			$sourceTypeList = ['js', 'css', 'files'];
			foreach ($sourceTypeList as $sourceType) {
				# Если в пакете присутствует необходимый тип ресурса
				if (isset($packageConfig[$sourceType])) {
					foreach ((array)$packageConfig[$sourceType] as $sourcePathMask) {
						if (isset($sourcePathMask['external']) && $sourcePathMask['external']) {
							continue;
						}

						$mask = isset($sourcePathMask['src']) ? $sourcePathMask['src'] : $sourcePathMask;
						$mask = $packageRelativeDirName . '/' . $mask;
						$files = Manager::getFilesByRelativeMask($mask);
						foreach ($files as $file) {
							$sourceFile = Publisher::getRealFilePath($file);
							$file = str_replace($packageRelativeDirName . '/', '', $file);
							$publishedFile = $publicDir . Publisher::getUri($file, false, $packageName);

							$sourceModificationTime = 0;
							$publishedModificationTime = 0;

							if (file_exists($sourceFile)) {
								$sourceModificationTime = md5_file($sourceFile);
							}

							if (file_exists($publishedFile)) {
								$publishedModificationTime = md5_file($publishedFile);
							}

							if ($sourceModificationTime !== $publishedModificationTime || $publishedModificationTime === false) {
								$packagesForPublish[$packageName] = $packageName;
							}
						}
					}
				}
			}
		}

		$republishGroupList = [];
		# Публикуем нужные пакеты
		foreach ($packagesForPublish as $packageForPublish) {
			$version =
				isset($runtimeConfigElements[$packageForPublish]) ?
					($runtimeConfigElements[$packageForPublish] + 1) :
					1;

			$republishGroupList = array_merge(
				$republishGroupList,
				static::getPackageGroups($packageForPublish)
			);
			Publisher::publishPackage($packageForPublish, $version);
		}

		foreach ((array)$republishGroupList as $group => $version) {
			Publisher::publishGroup($group, $version);
		}

		if (count($packagesForPublish) > 0) {
			if (function_exists('opcache_invalidate'))
			{
				if (file_exists(static::$runtimeConfigPath)) {
					if (!opcache_invalidate(static::$runtimeConfigPath, true)) {
						\Log::warn('resource manager', 'opcache_invalidate: false');
						exit;
					}
				} else {
					\Log::warn('resource manager', 'resource config file not found');
					exit;
				}
			}
		}
	}

	protected static function getPackageGroups($packageName)
	{
		$groupList = [];
		$groupsConfig = PackagesConfig::$groups;
		$publishedGroups = Publisher::getRuntimeConfig(true);

		foreach ($groupsConfig as $groupName => $groupPackages) {
			if (in_array($packageName, $groupsConfig[$groupName])) {
				$groupList[$groupName] = isset ($publishedGroups[$groupName]) ?
					(int)($publishedGroups[$groupName] + 1) : 1;
			}
		}

		return $groupList;
	}
}